;
;		CONSOLE.A86
;
DBIOS		EQU	50	;Access BIOS through BDOS
DCONSTAT	EQU	2	;BIOS console status
DCONIN		EQU	3	;BIOS console input
DCONOUT		EQU	4	;BIOS console out
DLIST		EQU	5	;BIOS list out
DLISTST		EQU	15	;BIOS list status
;	
;Console I/O routines for MODEM9.xx.
;
SHOW:
	CMP	AL,LF
	JZ	CTYPE
	CMP	AL,CR
	JZ	CTYPE
	CMP	AL,9
	JZ	CTYPE
	CMP	AL,' '
	JC	SHOWHEX
	CMP	AL,7FH
	JC	CTYPE
SHOWHEX:
	PUSH	AX
	MOV	AL,'('
	CALL	CTYPE
	POP	AX
	CALL	HEXO
	MOV	AL,')'
	JMP	CTYPE
;
CTYPE:
	PUSH	CX
	PUSH	DX
	PUSH	BX
	MOV	DL,AL
	MOV	CL,WRCON
	INT	224
	POP	BX
	POP	DX
	POP	CX
	RET
;
CRLF:
	PUSH	AX
	MOV	AL,CR
	CALL	TIPE
	MOV	AL,LF
	CALL	TIPE
	POP	AX
	RET
;
TIPE:
	PUSH	SI
	PUSH	CX
	PUSH	DX
	PUSH	BX
;	AND	AL,07FH
	MOV	Byte Ptr TBLOCK1,AL	
	MOV	CL,DBIOS
	MOV	DX,Offset TIPEBLOCK
	INT	224
	POP	BX
	POP	DX
	POP	CX
	POP	SI
	RET
;
TIPEBLOCK	DB	DCONOUT
TBLOCK1		DW	0
		DW	0	
;
STAT:
	PUSH	CX
	PUSH	DX
	PUSH	BX
	MOV	CL,DBIOS
	MOV	DX,Offset STATBLOCK
	INT	224
	POP	BX
	POP	DX
	POP	CX
	OR	AL,AL
	RET
;
STATBLOCK:
	DB	DCONSTAT
	DW	0
	DW	0
;
KEYIN:
	PUSH	CX
	PUSH	DX
	PUSH	BX
KEYIN1:
	MOV	CL,DBIOS
	MOV	DX,Offset KEYBLOCK
	INT	224
	POP	BX
	POP	DX
	POP	CX
	RET
;
KEYBLOCK:
	DB	DCONIN
	DW	0
	DW	0
;
LISTER:
	PUSH	CX
	PUSH	DX
	PUSH	BX
	MOV	CH,0		; MJM 9.01.05
	MOV	LBLOCK1,CX	; MJM 9.01.05
	MOV	DX,Offset LSTBLOCK
	MOV	CL,DBIOS
	INT	224
	POP	BX
	POP	DX
	POP	CX
	RET
;
LSTBLOCK	DB	DLIST
LBLOCK1		DW	0
		DW	0
;
LSTSTAT:
	PUSH	CX
	PUSH	DX
	PUSH	BX
	MOV	DX, OFFSET LSTSTATBLOCK
	MOV	CL,DBIOS
	INT	224
	POP	BX
	POP	DX
	POP	CX
	OR	AL,AL
	RET

LSTSTATBLOCK:
	DB	DLISTST
	DW	0
	DW	0
;
;
UCASE:
	CMP	AL,61H		;CHANGES LOWER CASE CHARACTER..
	JC	UCASERET	;..IN 'AL' REG TO UPPER CASE.
	CMP	AL,7BH
	JNC	UCASERET
	AND	AL,5FH
UCASERET:
	RET
;
DECOUT:
	PUSH	AX
	PUSH	CX
	PUSH	DX
	PUSH	BX
	MOV	CX, -10
	MOV	DX, -1
DECOU2:
	ADD	BX,CX
	INC	DX
	JC	DECOU2
	MOV	CX,OFFSET 10
	ADD	BX,CX
	XCHG	BX,DX
	MOV	AL,BH
	OR	AL,BL
	JZ	DECOU3
	CALL	DECOUT
DECOU3:
	MOV	AL,DL
	ADD	AL,'0'
	CALL	CTYPE
	POP	BX
	POP	DX
	POP	CX
	POP	AX
	RET
;
;---->	DHXOUT: - DOUBLE PRECISION HEX OUTPUT ROUTINE.
;
DHXOUT:
	PUSH	BX
	PUSH	AX
	MOV	AL,BH		;GET MS BYTE
	CALL	HEXO		;OUTPUT HIGH ORDER BYTE
	MOV	AL,BL		;GET LS BYTE
	CALL	HEXO		;OUTPUT LOW ORDER BYTE
	POP	AX
	POP	BX
	RET
;
HEXO:
	PUSH	AX
	RCR	AL,1
	RCR	AL,1
	RCR	AL,1
	RCR	AL,1
	CALL	NIBBL
	POP	AX
NIBBL:
	AND	AL,0FH
	CMP	AL,10
	JC	ISNUM
	ADD	AL,7
ISNUM:
	ADD	AL,'0'
	JMP	TIPE
;
SHFTYPE:
	PUSH	AX
	CALL	ILPRT
	DB	'ctrl-',0
	POP	AX
	ADD	AL,40H
	CALL	TIPE
;
;WRITE A STRING OF CHARACTERS
;
ILPRT:
	POP	SI
ILPLP:
	LODS	BYTE PTR [SI]
	OR	AL,AL
	JZ	ILPRET
	CALL	TIPE
	JMPS	ILPLP
ILPRET:
	PUSH	SI
	RET
;
;WRITE A STRING OF CHARACTERS EXCEPT IN QUIET MODE
;
ILPRTQ:
	POP	SI
ILPLPQ:
	LODS	BYTE PTR [SI]
	OR	AL,AL
	JZ	ILPRETQ
	TEST	QFLG,0FFH
	JZ	ILPLPQ1
	CALL	TIPE
ILPLPQ1:
	JMPS	ILPLPQ
ILPRETQ:
	PUSH	SI
	RET
;

;
;Duplicates 'read buffer' routine same as CP/M function 10,
;but does not use CTL-C (reason for the routine).  Does
;allow controls U, R, E and H (backspace).  Outputs bell if
;the input is greater than the buffer.
;
INBUFF:
	LAHF
	XCHG	AL,AH
	PUSH	AX
	XCHG	AL,AH
	PUSH	BX
	PUSH	CX
	PUSH	DX			;'DX' REGISTERS MUST BE PUSHED LAST
ISTART:
	CALL	CLEAR			;CLEAR THE BUFFER AREA
	POP	DX			;GET ADDRESS OF BUFFER ON RETRIES
	PUSH	DX			;RESTORE STACK
	XOR	AL,AL
	LAHF				;ADDRESS COUNT FIELD
	INC	DX
	SAHF
	MOV	SI,DX			;INITIALIZE WITH A ZERO IN COUNT BYTE
	MOV	[SI],AL
	LAHF
	INC	DX
	SAHF
	XCHG	BX,DX			;ADDRESS FIRST BUFFER BYTE WITH 'BX'
INBUFA:
	CALL	CONIN
	CMP	AL,CR			;IS IT A RETURN?
	JNZ	INBUFA_1	
	JMP	INBUFR			;IF SO, THEN RETURN
INBUFA_1:
	CMP	AL,7FH			;IS IT A DELETE?
	JZ	DELETE
	CMP	AL,8			;CTL-H WILL BACKSPACE..
	JZ	DELETE			;..OVER DELETED CHAR.
	CMP	AL,'U'-40H		;IS IT A CTL-U
	JNZ	INBUFA_2	
	JMP	INBUFO			;OUTPUT # CR-LF AND START OVER
INBUFA_2:
	CMP	AL,'R'-40H		;CTL-R RETYPES LINE
	JNZ	INBUFA_3	
	JMP	RETYPE
INBUFA_3:
	CMP	AL,'E'-40H
	JNZ	INBUFA_4	
	JMP	CRLF
INBUFA_4:
	CMP	AL,' '			;NO CONTROL CHARACTERS OTHER..
	JB	INBUFA			;..THAN ABOVE ALLOWED.
	MOV	CH,AL			;SAVE INPUTTED CHARACTER
	XCHG	BX,DX			;SAVE 'BX' IN 'DX'
	POP	BX			;GET ADDRESS OF BUFFER IN 'BX'
	PUSH	BX			;RESTORE STACK
	INC	BX			;ADDRESS COUNT BYTE
	INC	Byte Ptr [BX]		;INCREASE COUNT BYTE
	DEC	BX			;ADDRESS MAXIMUM
	MOV	AL,Byte Ptr [BX]	;PUT MAXIMUM IN 'AL'
	INC	BX			;ADDRESS COUNT
	CMP	AL,Byte Ptr [BX]	;COMPARE COUNT TO MAXIMUM
	JNB	INBUFA_5	
	JMP	ALERT			;IF MAXIMUM, RING BELL AND WAIT FOR CR
INBUFA_5:
	XCHG	BX,DX			;RESTORE BUFFER POINTER TO 'BX'
	MOV	Byte Ptr [BX],CH	;PUT INPUTTED CHARACTER IN BUFFER
	MOV	AL,CH			;OUTPUT IT
	CALL	TIPE
	LAHF				;BUMP POINTER
	INC	BX
	SAHF
	JMPS	INBUFA			;GET NEXT CHARACTER
;
DELETE:
	XCHG	BX,DX			;SAVE BUFFER POINTER IN 'DX'
	POP	BX			;ADDRESS BEGINNING OF BUFFER
	PUSH	BX			;RESTORE STACK
	INC	BX			;ADDRESS COUNT FIELD
	MOV	CH,AL			;SAVE DELETE CHAR - 7FH OR 08H
	MOV	AL,Byte Ptr [BX]
	SUB	AL,1			;DECREASE COUNT
	MOV	Byte Ptr [BX],AL
	JB	NODEL			;DON'T DELETE PAST BEGINING OF BUFFER.
	XCHG	BX,DX			;RESTORE BUFFER POINTER TO 'BX'
	DEC	BX			;POINT TO LAST BYTE INPUTTED
	MOV	AL,CH			;GET BACK EITHER 7FH OR 08H
	MOV	CH,Byte Ptr [BX]	;GET CHARACTER BEING DELETED
	MOV	Byte Ptr [BX],' '	;RESTORE BLANK
	CMP	AL,8
	JZ	BKSPC
	CMP	AL,7FH
	JZ	BKSPC0
	JMP	INBUFA			;GET NEXT CHARACTER
;
NODEL:
	INC	Byte Ptr [BX]		;DON'T LEAVE COUNT NEGATIVE
	XCHG	BX,DX			;RESTORE POINTER TO 'BX'
	JMP	INBUFA
;
BKSPC0:
	MOV	AL,08H
BKSPC:
	CALL	TIPE			;TRUE ERASE IF 08H
	MOV	AL,' '
	CALL	TIPE
	MOV	AL,8
	CALL	TIPE
	JMP	INBUFA
;
INBUFO:
	MOV	AL,'#'
	CALL	TIPE
	CALL	CRLF
	JMP	ISTART
;
RETYPE:
	POP	DX
	PUSH	DX
	LAHF				;POINT TO CURRENT NUMBER..
	INC	DX
	SAHF
	MOV	SI,DX			;..OF CHARACTERS.
	MOV	AL,[SI]
	MOV	CH,AL
	MOV	AL,'#'
	CALL	TIPE
	CALL	CRLF
	MOV	AL,CH			;TEST IF ZERO INPUT
	OR	AL,AL
	JNZ	CTLRLP	
	JMP	INBUFA
CTLRLP:
	LAHF
	INC	DX
	SAHF
	MOV	SI,DX
	MOV	AL,[SI]
	CALL	TIPE
	DEC	CH
	JNZ	CTLRLP
	JMP	INBUFA
;	
ALERT:
	MOV	AL,7
	CALL	TIPE
	DEC	Byte Ptr [BX]
	XCHG	BX,DX
	JMP	INBUFA
;
PCRLF:
	CALL	CRLF
	JMP	INBUFA
;
INBUFR:
	CALL	CRLF
	POP	DX
	POP	CX
	POP	BX
	POP	AX
	XCHG	AL,AH
	SAHF
	RET
;
CLEAR:
	POP	DX			;ACCOUNTS FOR CALL
	POP	BX			;ADDRESS BUFFER IN 'BX'
	PUSH	BX			;RESTORE..
	PUSH	DX			;..STACK
	MOV	CH,Byte Ptr [BX]	;SAVE MAXIMUM IN 'CH'
	LAHF				;POINT TO FIRST..
	INC	BX
	SAHF
	LAHF				;..BUFFER BYTE.
	INC	BX
	SAHF
	MOV	AL,' '
CLEARL:
	MOV	Byte Ptr [BX],AL
	LAHF
	INC	BX
	SAHF
	DEC	CH
	JNZ	CLEARL
	RET
;
CONIN:
	CALL	KEYIN
	CMP	AL,61H			;CHANGE TO UPPER..
	JB	NOUCASE			;..CASE SINCE CP/M..
	CMP	AL,7BH			;..DOES THE SAME.
	JNB	NOUCASE
	AND	AL,5FH
NOUCASE:
	RET
;
;Parses a CP/M buffer into format same as CP/M command line.
;
;Loads a command line addressed by 'DX' registers (max # characters in
;line in 'DX', number of characters in the line in 'DX'+1, line starts
;in 'DX'+2) into FCB addressed by 'BX' registers.  The FCB should be at
;least 33 bytes in length.  The command line buffer must have a maximum
;length of at least one more than the greatest number of characters
;that will be needed.
;
CPMLINE:
	PUSH	AX
	PUSH	CX
	PUSH	DX
	PUSH	BX
	CALL	CINIT		;FILLS FCBS WITH BLANKS AND NULLS
	XCHG	BX,DX		;GET START OF COMMAND LINE IN 'BX'
	INC	BX		;ADDRESS # BYTES IN CMD LINE
	MOV	DL,BYTE PTR [BX] ;LOAD 'DX' PAIR WITH # BYTES
	MOV	DH,0
	INC	BX
	ADD	BX,DX		;POINT TO BYTE AFTER LAST CHAR..
	MOV	BYTE PTR [BX],CR ;..IN CMD LINE AND STORE DELIMITER
	POP	BX		;RESTORE 'BX' AND 'DX'
	POP	DX
	PUSH	DX
	PUSH	BX
	INC	DX		;ADDRESS START OF COMMAND
	INC	DX
	CALL	DRIVE
NAME1:
	MOV	CL,8		;TRANSFER FIRST FILENAME TO FCB
	CALL	TRANS
	CMP	AL,CR
	JZ	CDONE
	CMP	AL,' '		;IF SPACE, THEN START OF..
	JZ	NAME2		;..SECOND FILENAME.
TYPE1:
	POP	BX		;FILETYPE MUST BE AFTER..
	PUSH	BX		;..EIGHTH BYTE OF NAME
	MOV	CX, 9
	ADD	BX,CX
	MOV	CL,3		;TRANSFER TYPE OF FIRST FILE
	CALL	TRANS
	CMP	AL,CR
	JZ	CDONE
NAME2:
	XCHG	BX,DX
	MOV	AL,BYTE PTR [BX]	;EAT MULTIPLE SPACES..
	XCHG	BX,DX
	CMP	AL,' '		;..BETWEEN NAMES
	JNZ	NAME2C
	INC	DX
	JMP	NAME2
NAME2C:
	POP	BX		;SECOND NAME STARTS IN 16TH BYTE
	PUSH	BX		;POINT 'BX' TO THIS BYTE
	MOV	CX, 16
	ADD	BX,CX
	CALL	DRIVE
	MOV	CL,8
	CALL	TRANS
	CMP	AL,CR
	JZ	CDONE
TYPE2:
	POP	BX		;SECOND TYPE STARTS IN 25TH BYTE.
	PUSH	BX
	MOV	CX,OFFSET 25
	ADD	BX,CX
	MOV	CL,3
	CALL	TRANS
CDONE:
	POP	BX
	PUSH	BX
	INC	BX		;POINT TO 1ST CHAR OF 1ST NAME IN FCB
	CALL	CSCAN		;CHECK FOR * (AMBIGUOUS NAMES).
	POP	BX
	PUSH	BX
	MOV	CX,OFFSET 17	;POINT TO 1ST CHAR OF 2ND NAME IN FCB.
	ADD	BX,CX
	CALL	CSCAN
	POP	BX
	POP	DX
	POP	CX
	POP	AX
	RET
;
CINIT:
	PUSH	BX		;INITIALIZES FCB WITH 1 NULL (FOR 1ST DRIVE),..
	PUSH	CX		;..11 BLANKS, 4 NULLS, 1 NULL (FOR 2ND DRIVE)..
	MOV	BYTE PTR [BX],0	;..11 BLANKS, AND 4 NULLS
	INC	BX
	MOV	CH,11
	MOV	AL,' '
	CALL	INITFILL
	MOV	CH,5
	MOV	AL,0
	CALL	INITFILL
	MOV	CH,11
	MOV	AL,' '
	CALL	INITFILL
	MOV	CH,4
	MOV	AL,0
	CALL	INITFILL
	POP	CX
	POP	BX
	RET
;
INITFILL:
	MOV	BYTE PTR [BX],AL
	INC	BX
	DEC	CH
	JNZ	INITFILL
	RET
;
DRIVE:
	INC	DX		;CHECK 2ND BYTE OF FILENAME. IF IT..
	XCHG	BX,DX
	MOV	AL,BYTE PTR [BX]	;..IS A ":", THEN DRIVE WAS SPECIFIED
	XCHG	BX,DX
	DEC	DX
	CMP	AL,':'
	JNZ	DEFDR		;ELSE ZERO FOR DEFAULT DRIVE ('INIT' PUT ZERO)
	XCHG	BX,DX
	MOV	AL,BYTE PTR [BX]
	XCHG	BX,DX
	AND	AL,5FH
	SUB	AL,40H		;CALCULATE DRIVE (A=1, B=2,...)..
	MOV	BYTE PTR [BX],AL	;..AND PLACE IT IN FCB
	INC	DX		;ADDRESS FIRST BYTE OF..
	INC	DX		;..IN CMD LINE..
DEFDR:
	INC	BX		;..AND NAME FIELD IN FCB
DEFDRRET:
	RET
;
TRANS:
	XCHG	BX,DX
	MOV	AL,BYTE PTR [BX]
	XCHG	BX,DX		;TRANSFER FROM CMD LINE TO FCB..
	INC	DX		;..UP TO NUMBER OF CHARS SPECIFIED..
	CMP	AL,CR		;..BY 'CL' REG. KEEP SCANNING FIELD..
	JZ	DEFDRRET	;..WITHOUT TRANSFER UNTIL A DELIMITING..
	CMP	AL,'.'		;..FIELD CHAR SUCH AS '.', BLANK, OR..
	JZ	DEFDRRET	;..C/R (FOR END OF CMD LINE)
	CMP	AL,' '
	JZ	DEFDRRET
	DEC	CL
	JB	TRANS		;ONCE 'CL' REG IS LESS THAN '0' KEEP READING
	MOV	BYTE PTR [BX],AL	;..CMD LINE BUT DO NOT TRANSFER TO FCB
	INC	BX
	JMP	TRANS
;
CSCAN:
	MOV	CH,8		;SCAN FILE NAME ADDRESSED BY 'BX'
TSTNAM:
	MOV	AL,BYTE PTR [BX]
	CMP	AL,'*'		;IF '*' FOUND, FILL IN REST OF FIELD..
	JZ	FILL1		;..WITH '?' FOR AMBIGUOUS NAME
	INC	BX
	DEC	CH
	JNZ	TSTNAM
	JMP	TSTTYP
;
FILL1:
	CALL	FILL
TSTTYP:
	MOV	CH,3		;SCAN AND FILL TYPE FIELD FOR NAME..
TSTTYPL:
	MOV	AL,BYTE PTR [BX]	;..SPECIFIED ABOVE
	CMP	AL,'*'
	JZ	FILL2
	INC	BX
	DEC	CH
	JZ	FILL2RET
	JMP	TSTTYPL
;
FILL2:
	CALL	FILL
FILL2RET:
	RET
;
FILL:
	MOV	BYTE PTR [BX],'?'	;ROUTINE TRANSFERS '?'
	INC	BX
	DEC	CH
	JNZ	FILL
	RET
;
;
;In-line compare.  Compares string addressed by 'DX' pair to string af-
;the call (ends with '0').  Return with carry set means strings not the
;same.  All registers (except 'AL') are unaffected.
;
ILCOMP:
	POP	SI		; POINT 'SI' TO 1ST CHARACTER
	PUSH	BX
	MOV	BX,SI
	PUSH	DX
ILCOMPL:
	MOV	AL,BYTE PTR [BX] ; 'BX' POINTS TO IN-LINE STRING
	OR	AL,AL		;END OF STRING IF ZERO
	JZ	SAME
	XCHG	BX,DX
	MOV	AL,BYTE PTR [BX]
	XCHG	BX,DX
	CMP	AL,BYTE PTR [BX]
	JNZ	NOTSAME
	INC	BX
	INC	DX
	JMP	ILCOMPL
;
NOTSAME:
	MOV	AL,0		;IF NOT SAME, FINISH THRU..
NSLP:
	INC	BX		;..STRING SO RETURN WILL..
	CMP	AL,BYTE PTR [BX]	;..GO TO INSTRUCTION AFTER..
	JNZ	NSLP		;..STRING AND NOT REMAINDER OF STRING
	STC
SAME:
	POP	DX
	INC	BX		;AVOIDS A NOP INSTRUCTION..
	MOV	SI,BX		;..WHEN RETURNING
	POP	BX
	PUSH	SI
	RET
;
